home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_ImportAdv / Document.m < prev    next >
Text File  |  1992-12-19  |  20KB  |  811 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *     Document.m
  35.  *
  36.  *    Portions of the source code in this file are based on source code
  37.  *    from the Draw example application provided by NeXT.
  38.  *
  39.  *    The Document class serves to keep track of the global information
  40.  *    concerning a particular file. It sets up the window and the views
  41.  *    (ScrollView, DocView and DrawingView) . It manages the name
  42.  *    of the file as well as save and print info information.
  43.  *
  44.  *    The listenerId is used to allow the user to drag an icon representing
  45.  *    a PostScript file into the document.  The iconPathList is the
  46.  *    list of files which was last dragged into the document.
  47.  *
  48.  *    The saved variable marks whether a disk file has been
  49.  *    created for the document (i.e. if it has ever been saved).
  50.  *
  51.  *    Version:    2.0
  52.  *    Author:    Ken Fromm
  53.  */
  54.  
  55. #import "Document.h"
  56. #import "ImportApp.h"
  57. #import "DocView.h"
  58. #import "DrawingView.h"
  59. #import "ScrollingView.h"
  60. #import "ImportPanel.h"
  61. #import "SaveAsPanel.h"
  62.  
  63. #import <appkit/Cursor.h>
  64. #import <appkit/Listener.h>
  65. #import <appkit/Matrix.h>
  66. #import <appkit/PageLayout.h>
  67. #import <appkit/PrintInfo.h>
  68. #import <appkit/ScrollView.h>
  69. #import <appkit/Speaker.h>
  70. #import <appkit/nextstd.h>
  71. #import <appkit/publicWraps.h>
  72. #import <objc/hashtable.h>
  73. #import <string.h>
  74.  
  75. const NXRect            DefaultContentRect = {0.0, 0.0, 575.0, 660.0};
  76. static const char         DefaultName[] = "Empty Window";
  77.  
  78. extern void resizeBuffer();
  79.  
  80. @implementation Document
  81.  
  82. /* Factory methods */
  83.  
  84. /*
  85.  * Creates a new, empty, document.
  86.  *
  87.  * Creates a PrintInfo object; creates a view whose size depends on the
  88.  * default PrintInfo created; creates a window for that view; sets self
  89.  * as the window's delegate; orders the window front; registers the window
  90.  * with the Workspace Manager.  The default margins are set to 1/4 inch.
  91.  */
  92. + new
  93. {
  94.     self = [super new];
  95.  
  96.     printinfoId = [PrintInfo  new];
  97.     [printinfoId setMarginLeft:18.0 right:18.0 top:18.0 bottom:18.0];
  98.  
  99.     [self  createWindow];
  100.     [self  setName:NULL andDirectory:NULL];
  101.     [self  setDocument];
  102.  
  103.     return self;
  104. }
  105.  
  106. /* Opens an existing document from the specified file. */
  107. + newFromFile:(const char *)file
  108. {
  109.     NXStream        *stream;
  110.  
  111.     self = [super new];
  112.     stream = NXMapFile(file, NX_READONLY);
  113.  
  114.     [self  createWindow];                
  115.     if ([self  readFromStream:stream])
  116.     {
  117.         [self  setName:file];
  118.         [self  setDocument];
  119.     }
  120.     else
  121.     {
  122.         [self  free];
  123.         self = nil;
  124.     }
  125.         
  126.     return self;
  127. }
  128.  
  129. /* Very private instance method needed by factory methods */
  130.  
  131. /*
  132.  *    This method loads an archived document from the
  133.  *    specified file name. The frame size is read first and then
  134.  *    the window is displayed before the rest of the document
  135.  *    is loaded (the print info and the drawing view).
  136.  *    
  137.  *    Does not place newView as the window's drawing view until
  138.  *    the read is complete. If a failure occurs for some reason
  139.  *    during the read, the previous drawing view is retained.
  140.  *
  141.  *    An NX_DURING handler is needed around the NXTypedStream
  142.  *    operations because if the user has asked that a bogus file be
  143.  *    opened, the NXTypedStream will raise an error.  To handle the
  144.  *    error, the NXTypedStream must be closed.
  145.  */
  146. - readFromStream:(NXStream *)stream
  147. {
  148.     BOOL                err = YES;
  149.  
  150.     NXTypedStream        *volatile ts = NULL;
  151.  
  152.     if (stream)
  153.     {
  154.         NX_DURING
  155.             ts = NXOpenTypedStream(stream, NX_READONLY);
  156.             if (ts)
  157.             {
  158.                 printinfoId = NXReadObject(ts);
  159.                 drawingviewId = NXReadObject(ts);
  160.                 NXCloseTypedStream(ts);
  161.                 err = NO;
  162.             }
  163.         NX_HANDLER
  164.             NXCloseTypedStream(ts);
  165.         NX_ENDHANDLER
  166.  
  167.         NXClose(stream);
  168.     }
  169.  
  170.     if (!err)
  171.     {
  172.         [[docviewId  setDrawView:drawingviewId]  free];
  173.         [docviewId  placeView:drawingviewId];
  174.         [[windowId  contentView]  display];
  175.     }
  176.     else
  177.         Notify("Open Error", "Cannot open file.");
  178.  
  179.     return self;
  180. }
  181.  
  182. - setDocument
  183. {
  184.     NXPoint        location;
  185.  
  186.     NXRect        winFrame;
  187.  
  188.     [docviewId  placeView:drawingviewId];
  189.  
  190.     [self  registerWindow];
  191.     [windowId  setDelegate:self];
  192.     [windowId  display];
  193.     
  194.     [windowId  getFrame:&winFrame];
  195.     [NXApp  getPosition:&location  forSize:&winFrame.size];
  196.     [windowId  moveTo:location.x  :location.y];
  197.  
  198.     [windowId  makeKeyAndOrderFront:self];
  199.  
  200.     return self;
  201. }
  202.  
  203. - free
  204. {
  205.     [printinfoId free];
  206.     [windowId free];
  207.  
  208.     NX_FREE(name);
  209.     NX_FREE(directory);
  210.     NX_FREE(iconPathList);
  211.  
  212.     return [super free];
  213. }
  214.  
  215. /*
  216. *    Create the drawing window and place a scrollview as the content view.
  217. *    A DrawingView instance is placed as the DocView of the ScrollView.
  218. */
  219. - createWindow
  220. {
  221.     id                scrollView;
  222.  
  223.     const NXRect        *paperRect;
  224.  
  225.     windowId = [Window newContent:&DefaultContentRect
  226.             style:NX_TITLEDSTYLE
  227.             backing:NX_BUFFERED
  228.             buttonMask:NX_ALLBUTTONS
  229.             defer:NO];
  230.     [windowId  addToEventMask:NX_FLAGSCHANGEDMASK];
  231.  
  232.     scrollView = [ScrollingView  newFrame:&DefaultContentRect];
  233.     [scrollView  setBorderType:SCROLLVIEW_BORDER];
  234.  
  235.     paperRect =  [printinfoId  paperRect];
  236.     drawingviewId = [DrawingView  newFrame:paperRect];
  237.     docviewId = [[[[DocView new]  setClipping:NO] setScale:1.0]  setFlipped:NO];
  238.     [docviewId  notifyAncestorWhenFrameChanged:YES];
  239.  
  240.     [docviewId  setDrawView:drawingviewId];
  241.     [scrollView  setDocView:docviewId];
  242.     [[docviewId  superview]  allocateGState];
  243.  
  244.     [[windowId  setContentView:scrollView] free];
  245.  
  246.     [windowId  makeFirstResponder:drawingviewId];
  247.  
  248.     return self;
  249. }
  250.  
  251. - window
  252. {
  253.     return windowId;
  254. }
  255.  
  256. /*  Returns the DrawingView associated with this document.  */
  257. - drawingView
  258. {
  259.     return drawingviewId;
  260. }
  261.  
  262. - docView
  263. {
  264.     return docviewId;
  265. }
  266.  
  267. - printInfo
  268. {
  269.     return printinfoId;
  270. }
  271.  
  272. /* Target/Action methods */
  273. /*
  274.  * Puts up a PageLayout panel and allows the user to pick a different
  275.  * size paper to work on.  The view is then resized to the
  276.  * new paper size. The new DrawingView is placed in the DocView
  277.  * and then scrolled to the previous rectangle.
  278.  * The view is dirtied because the PrintInfo is part of the document.
  279.  */
  280. - changeLayout:sender
  281. {
  282.     NXRect            visibleRect;
  283.     const NXRect        *paperRect;
  284.  
  285.     if ([[PageLayout new] runModal] == NX_OKTAG)
  286.     {
  287.         [drawingviewId getVisibleRect:&visibleRect];
  288.         paperRect = [printinfoId  paperRect];
  289.         [drawingviewId sizeTo:paperRect->size.width :paperRect->size.height];
  290.         [docviewId  placeView:drawingviewId];
  291.         [drawingviewId scrollRectToVisible:&visibleRect];
  292.         [[windowId  contentView] display];
  293.         [drawingviewId setDirty:YES];
  294.     }
  295.  
  296.     return self;
  297. }
  298.  
  299. - print:sender
  300. {
  301.     return [drawingviewId  printPSCode:sender];
  302. }
  303.  
  304. /*  Revert the document back to what is on the disk.  */ 
  305. - revertToSaved:sender
  306. {
  307.     NXStream        *stream;
  308.     NXRect            visibleRect;
  309.     const NXRect        *paperRect;
  310.  
  311.     if (!saved || ![drawingviewId isDirty] ||
  312.         (NXRunAlertPanel("Revert",
  313.             "%s has been edited.  Are you sure you want to undo changes?", 
  314.             "Revert", "Cancel", NULL, name) != NX_ALERTDEFAULT))
  315.     {
  316.         return self;
  317.     }
  318.  
  319.     [drawingviewId getVisibleRect:&visibleRect];
  320.     [windowId endEditingFor:self];
  321.  
  322.     stream = NXMapFile([self filename], NX_READONLY);
  323.     if (stream && [self readFromStream:stream])
  324.     {
  325.         [windowId disableDisplay];
  326.             paperRect = [printinfoId  paperRect];
  327.             [drawingviewId sizeTo:paperRect->size.width :paperRect->size.height];
  328.             [docviewId  placeView:drawingviewId];
  329.             [drawingviewId scrollRectToVisible:&visibleRect];
  330.             [windowId reenableDisplay];
  331.         [[windowId contentView]  display];
  332.         [windowId makeFirstResponder:drawingviewId];
  333.         [drawingviewId setDirty:NO];
  334.         NXClose(stream);
  335.     }
  336.     else
  337.     {
  338.         if (stream)
  339.             NXClose(stream);
  340.         Notify("Revert Error", "Cannot revert to saved file.");
  341.     }
  342.  
  343.     return self;
  344. }
  345.  
  346. /*
  347. *    Bring up the import (open) panel to obtain the file and then pass
  348. *    to the drawing view.
  349. */
  350.  
  351. - import:sender
  352. {
  353.     id                        importpanel;
  354.  
  355.     static const char *const        filetype[4] = {"ps", "eps", "tiff", NULL};
  356.  
  357.     importpanel = [[ImportPanel  new]  setImport];
  358.     if ([importpanel runModalForTypes:filetype])
  359.         [drawingviewId  importFile:[importpanel  filename]  at:NULL];
  360.  
  361.     return self;
  362. }
  363.  
  364. /*
  365.  *    Writes out the document in archive format.
  366.  *    (Saves the PrintInfo and DrawingView objects. See
  367.  *    DrawingView's write: methods for more details.)
  368.  */
  369. - saveFile:(const char *) file
  370. {
  371.     BOOL            error;
  372.  
  373.     NXTypedStream    *typedstream;
  374.  
  375.     error = YES;
  376.     typedstream = NXOpenTypedStreamForFile(file, NX_WRITEONLY);
  377.     if (typedstream)
  378.     {
  379.         NXWriteRootObject(typedstream, printinfoId);
  380.         NXWriteRootObject(typedstream, drawingviewId);
  381.         NXCloseTypedStream(typedstream);
  382.         error = NO;
  383.     }
  384.     else
  385.         Notify("Save Error", "Cannot open a typed stream to the file.");
  386.  
  387.     return (error ? nil : self);
  388. }
  389.  
  390. /*
  391.  * Saves the file.  If this document has never been saved to disk,
  392.  * then a SavePanel is put up to ask the user what file name she
  393.  * wishes to use to save the document.
  394.  */
  395. - save:sender
  396. {
  397.     id        savepanel;
  398.  
  399.     if ([drawingviewId isDirty] || !saved)
  400.     {
  401.         if (!saved)
  402.         {
  403.             savepanel = [[SaveAsPanel  new]  setSave];
  404.             if (![savepanel    runModalForDirectory:directory  file:NULL])
  405.                 return self;
  406.  
  407.             [self  setName:[savepanel  filename]];
  408.         }
  409.  
  410.         if ([self  saveFile:[self  filename]])
  411.         {
  412.             [drawingviewId  setDirty:NO];
  413.             saved = YES;
  414.         }
  415.     }
  416.  
  417.     return self;
  418. }
  419.  
  420. - saveAs:sender
  421. {
  422.     id        savepanel;
  423.  
  424.     char        *tempname;
  425.  
  426.     if (strcmp(name, DefaultName) == 0)
  427.         tempname = NULL;
  428.     else
  429.         tempname = name;
  430.  
  431.     savepanel = [[SaveAsPanel  new]  setSaveAs];
  432.     if ([savepanel    runModalForDirectory:directory  file:tempname])
  433.     {
  434.         [drawingviewId setDirty:YES];
  435.         [self  setName:[savepanel  filename]];
  436.         if ([self  saveFile:[self  filename]])
  437.         {
  438.             [drawingviewId  setDirty:NO];
  439.             saved = YES;
  440.         }
  441.     }
  442.     
  443.     return self;
  444. }
  445.  
  446.  /*
  447.  *    Writes out the document in Epsf/Illustrator format.
  448.  */
  449. - saveTo:sender
  450. {
  451.     id            savepanel;
  452.  
  453.     NXStream    *stream;
  454.  
  455.     savepanel = [[SaveAsPanel  new]  setSaveTo];
  456.     if ([savepanel    runModal])
  457.     {    
  458.         stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  459.         if (stream)
  460.         {
  461.             [drawingviewId  writePSToStream:stream];
  462.             NXSaveToFile(stream, [savepanel  filename]);
  463.             NXCloseMemory(stream, NX_FREEBUFFER);
  464.         }
  465.         else
  466.             Notify("Save Error", "Cannot open a stream to the file.");
  467.     }
  468.  
  469.     return self;
  470. }
  471.  
  472. /* Methods related to naming/saving this document. */
  473. /*
  474.  *    Gets the fully specified file name of the document.
  475.  */
  476. - (const char *)filename
  477. {
  478.     static char        filenamebuf[MAXPATHLEN+1];
  479.  
  480.     if (!directory || !name)
  481.         [self  setName:name andDirectory:directory];
  482.  
  483.     if (directory)
  484.     {
  485.         strcpy(filenamebuf, directory);
  486.         strcat(filenamebuf, "/");
  487.     }
  488.     else
  489.         filenamebuf[0] = '\0';
  490.  
  491.     if (name)
  492.         strcat(filenamebuf, name);
  493.  
  494.     return filenamebuf;
  495. }
  496.  
  497. - (const char *)directory
  498. {
  499.     return directory;
  500. }
  501.  
  502. - (const char *)name
  503. {
  504.     return name;
  505. }
  506.  
  507. /*
  508.  * If file is a full path name, then both the name and directory of the
  509.  * document is updated appropriately, otherwise, only the name is changed.
  510.  */
  511. - setName:(const char *)file
  512. {
  513.     char        *lastComponent;
  514.     char        path[MAXPATHLEN+1];
  515.  
  516.     if (file)
  517.     {
  518.         strcpy(path, file);
  519.         lastComponent = strrchr(path, '/');
  520.         if (lastComponent)
  521.         {
  522.             *lastComponent++ = '\0';
  523.             return [self setName:lastComponent andDirectory:path];
  524.         }
  525.         else
  526.             return [self setName:file andDirectory:NULL];
  527.     }
  528.  
  529.     return self;
  530. }
  531.  
  532. /*
  533.  * Updates the name and directory of the document.
  534.  * newName or newDirectory can be NULL, in which case the name or directory
  535.  * will not be changed (unless one is currently not set, in which case
  536.  * a default name will be used).
  537.  */
  538. - setName:(const char *)newName andDirectory:(const char *)newDirectory
  539. {
  540.     if ((newName && *newName) || !name)
  541.     {
  542.         if (!newName || !*newName)
  543.             newName = DefaultName;
  544.         NX_FREE(name);
  545.         name = NXCopyStringBuffer(newName);
  546.     }
  547.  
  548.     if ((newDirectory && (*newDirectory == '/')) || !directory)
  549.     {
  550.         if (!newDirectory || (*newDirectory != '/'))
  551.             newDirectory = [NXApp currentDirectory];
  552.         NX_FREE(directory);
  553.         directory = NXCopyStringBufferFromZone(newDirectory, [self zone]);
  554.     }
  555.     [windowId  setTitleAsFilename:[self  filename]];
  556.  
  557.     return self;
  558. }
  559.  
  560. /* Window delegate methods. */
  561.  
  562. /*
  563.  * Switch the Application's PrintInfo to the document's when the document
  564.  * window becomes the main window.  Also set the cursor appropriately
  565.  * depending on which tool is currently selected.
  566.  */
  567. - windowDidBecomeMain:sender
  568. {
  569.     [NXApp setPrintInfo:printinfoId];
  570.     [self  resetResponder];
  571.  
  572.     return self;
  573. }
  574.  
  575. /*
  576.  *    Prevents the window from getting too large or too small.
  577.  */
  578. - windowWillResize:sender toSize:(NXSize *)size
  579. {
  580.     NXSize    screenSize;
  581.     
  582.     [NXApp  getScreenSize:&screenSize];
  583.     screenSize.width = screenSize.width * 0.90;
  584.     screenSize.height = screenSize.height * 0.90;
  585.  
  586.     size->width = MIN(screenSize.width, size->width);
  587.     size->height = MIN(screenSize.height, size->height);
  588.     
  589.     size->width = MAX(MIN_WINDOW_WIDTH, size->width);
  590.     size->height = MAX(MIN_WINDOW_HEIGHT, size->height);
  591.  
  592.     return self;
  593. }
  594.  
  595. /*
  596.  * Resizes the doc view and repositions the drawing view inside the doc view.
  597.  */
  598. - windowDidResize:sender
  599. {
  600.     NXRect        frameRect, contRect;
  601.  
  602.     [windowId  getFrame:&frameRect];
  603.     [Window  getContentRect:&contRect  forFrameRect:&frameRect  style:[windowId  style]];
  604.     resizeBuffer([drawingviewId  buffer], &contRect.size);
  605.  
  606.     [docviewId  placeView:drawingviewId];
  607.  
  608.     return self;
  609. }
  610.  
  611. /*
  612.  * If the GraphicView has been edited, then this asks the user if she
  613.  * wants to save the changes before closing the window.  When the window
  614.  * is closed, the DrawDocument itself must be freed.  This is accomplished
  615.  * via Application's delayedFree: mechanism.  Unfortunately, by the time
  616.  * delayedFree: frees the DrawDocument, the window and view instance variables
  617.  * will already have automatically been freed by virtue of the window's being
  618.  * closed.  Thus, those instance variables must be set to nil to avoid their
  619.  * being freed twice.
  620.  *
  621.  * Returning nil from this method informs the caller that the window should
  622.  * NOT be closed.  Anything else implies it should be closed.
  623.  */
  624. - windowWillClose:sender
  625. {
  626.     int save;
  627.  
  628.     if ([drawingviewId isDirty] && (saved || ![drawingviewId isEmpty]))
  629.     {
  630.         save = NXRunAlertPanel("Close", "%s has changes. Save them?", "Save",
  631.                 "Don't Save", "Cancel", name);
  632.         if (save == NX_ALERTDEFAULT || save == NX_ALERTALTERNATE)
  633.         {
  634.             [sender endEditingFor:self];    /* terminate any editing */
  635.             if (save == NX_ALERTDEFAULT)
  636.                 [self save:nil];
  637.         }
  638.         else
  639.             return nil;
  640.     }
  641.  
  642.     [self unregisterWindow];
  643.  
  644.     [NXApp setPrintInfo:nil];
  645.  
  646.     return self;
  647. }
  648.  
  649. /* Icon dragging methods */
  650.  
  651. /*
  652.  * Registers the document window with the Workspace Manager so that when the
  653.  * user picks up an icon in the Workspace and drags it over our document window
  654.  * and lets go, iconEntered:... and iconReleasedAt::ok: messages will be
  655.  * sent to the DrawDocument from the Workspace Manager.  Allows the user to
  656.  * drag PostScript and TIFF files into the document.
  657.  */
  658. - registerWindow
  659. {
  660.     unsigned int    windowNum;
  661.     id            speaker = [NXApp appSpeaker];
  662.  
  663.     listenerId = [Listener new];
  664.     [listenerId setDelegate:self];
  665.     [listenerId usePrivatePort];
  666.     [listenerId addPort];
  667.     
  668.     NXConvertWinNumToGlobal([windowId windowNum], &windowNum);
  669.     [speaker setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
  670.     [speaker registerWindow:windowNum toPort:[listenerId listenPort]];
  671.  
  672.     return self;
  673. }
  674.  
  675. /*  Undoes what registerWindow does.  */
  676. - unregisterWindow
  677. {
  678.     unsigned int        windowNum;
  679.     id                speaker = [NXApp appSpeaker];
  680.  
  681.     if (listenerId)
  682.     {
  683.         [speaker  setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
  684.         NXConvertWinNumToGlobal([windowId windowNum], &windowNum);
  685.         [speaker  unregisterWindow:windowNum];
  686.         [listenerId free];
  687.     }
  688.  
  689.     return self;
  690. }
  691.  
  692. /*
  693.  * Called whenever an icon is dragged from the Workspace over the document
  694.  * window.  At this point, all that is done is to salt away the list of files
  695.  * represented by the icon.  All the real work is done in iconReleasedAt::ok:.
  696.  */
  697. - (int)iconEntered:(int)windowNum at:(double)x :(double)y
  698.     iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY
  699.     iconWidth:(double)iconWidth iconHeight:(double)iconHeight
  700.     pathList:(char *)pathList
  701. {
  702.     if (!iconPathList || strcmp(iconPathList, pathList))
  703.     {
  704.         NX_FREE(iconPathList);
  705.         NX_MALLOC(iconPathList, char, strlen(pathList)+1);
  706.         strcpy(iconPathList, pathList);
  707.     }
  708.     return 0;
  709. }
  710.  
  711. /*
  712.  * Goes through the list of files associated with the icon dragged
  713.  * from the Workspace and checks if any of them are PostScript or TIFF.
  714.  * If any are, then the GraphicView is asked to load those in as objects.
  715.  * Very important: an NX_DURING handler is required around all the processing
  716.  * of this method since an uncaught raised error will cause this method not
  717.  * to return and thus hang the Workspace Manager for a while.
  718.  */
  719. - (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
  720. {
  721.     volatile int        foundOne = NO;
  722.     char                *file, *tab, *extension;
  723.  
  724.     int                format;
  725.  
  726.     id                importpanel;
  727.  
  728.     NXPoint            pt;
  729.  
  730.     NX_DURING
  731.         importpanel = [ImportPanel  new];
  732.         format = [importpanel  format];
  733.         [importpanel  setFormat:IMPORT_COPY];
  734.  
  735.         pt.x = x;
  736.         pt.y = y;
  737.         [windowId  convertScreenToBase:&pt];
  738.         [drawingviewId  convertPoint:&pt fromView:nil];
  739.         file = iconPathList;
  740.         while (file)
  741.         {
  742.             tab = strchr(file, '\t');
  743.             if (tab)
  744.                 *tab = '\0';
  745.             extension = strrchr(file, '.');
  746.             if (extension)
  747.             {
  748.                 if (!strcmp(extension, ".ps") ||
  749.                     !strcmp(extension, ".eps") ||
  750.                         !strcmp(extension, ".tiff"))
  751.                     if ([drawingviewId  importFile:file  at:&pt])
  752.                         foundOne = YES;
  753.             }
  754.             file = tab ? tab++ : NULL;
  755.         }
  756.         if (foundOne)
  757.         {
  758.             [NXApp activateSelf:YES];
  759.             [windowId makeKeyAndOrderFront:self];
  760.         }
  761.         [importpanel  setFormat:format];
  762.     NX_HANDLER
  763.     NX_ENDHANDLER
  764.  
  765.     *flag = foundOne;
  766.  
  767.     return 0;
  768. }
  769.  
  770. /* Validates whether a menu command makes sense now */
  771.  
  772. /*
  773.  * Validates whether a menu command that DrawDocument responds to
  774.  * is valid at the current time.
  775.  */
  776. - (BOOL)validateCommand:menuCell
  777. {
  778.     SEL action = [menuCell action];
  779.  
  780.     if (action == @selector(save:))
  781.         return ([drawingviewId  isDirty] || !saved);
  782.     else if (action == @selector(saveTo:))
  783.         return ([drawingviewId  isSelected]);
  784.     else if (action == @selector(revertToSaved:))
  785.         return ([drawingviewId  isDirty] && saved);
  786.  
  787.     return YES;
  788. }
  789.  
  790. /* Cursor-setting method */
  791.  
  792. /*
  793.  *    Resets the document's cursor rectangle to be the frame of the
  794.  *    drawing view.
  795.  *    Makes the drawing view the first responder if
  796.  *    there isn't one or if no tool is selected.
  797.  */
  798. - resetResponder
  799. {
  800.     id            responder;
  801.  
  802.     responder = [windowId  firstResponder];
  803.     if (!responder || responder == windowId || [NXApp  cursor] == NXArrow)
  804.         [windowId makeFirstResponder:drawingviewId];
  805.  
  806.     return self;
  807. }
  808.  
  809. @end
  810.  
  811.